package com.czk.netty.nio.chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;

/**
 * 去聊服务端
 *
 * @Author:ChenZhangKun
 * @Date: 2021/1/12 20:46
 */
public class GroupChatServer {
    /**
     * 选择器
     */
    private Selector selector;
    /**
     * 服务器监听
     */
    private ServerSocketChannel listen;
    /**
     * 端口
     */
    private static final int PORT = 6667;

    public GroupChatServer() {
        try {
            selector = Selector.open();
            listen = ServerSocketChannel.open();
            // 绑定端口
            listen.bind(new InetSocketAddress(PORT));
            // 配置非阻塞模式
            listen.configureBlocking(false);
            // 将listen注册到selector
            listen.register(selector, SelectionKey.OP_ACCEPT);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 监听
     */
    public void listen() {
        try {
            while (true) {
                int count = selector.select();
                if (count > 0) {
                    // 有事件处理
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        // 取出selectionKey
                        SelectionKey key = iterator.next();
                        // 监听key的事件
                        // 是连接事件
                        if (key.isAcceptable()) {
                            // 连接事件
                            // 拿到channel
                            SocketChannel socketChannel = listen.accept();
                            // 配置非阻塞
                            socketChannel.configureBlocking(false);
                            // 注册
                            socketChannel.register(selector, SelectionKey.OP_READ);
                            // 提示用户上线
                            System.out.println(socketChannel.getRemoteAddress() + " 上线了 ");
                        }
                        if (key.isReadable()) {
                            // 是读事件，处理读
                            System.out.println("进入读处理了");
                            readData(key);
                        }
                        // 删除key,防止重复处理
                        iterator.remove();
                    }
                } else {
                    // 等待
                    System.out.println("服务器等待中");
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {

        }
    }

    /**
     * 读取客户端消息
     *
     * @param selectionKey
     */
    public void readData(SelectionKey selectionKey) {
        SocketChannel socketChannel = null;
        try {
            // 反向得到对应的channel
            socketChannel = (SocketChannel) selectionKey.channel();
            // 创建buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 读取数据
            int count = socketChannel.read(buffer);
            if (count != -1) {
                // 把缓冲区数据输出
                String message = new String(buffer.array());
                System.out.println("客户端" + socketChannel.getRemoteAddress() + ":" + message);
                // 向其他的客户端转发消息
                sendMessageToOtherClient(message, socketChannel);
            }
        } catch (IOException ex) {
            try {
                System.out.println(socketChannel.getRemoteAddress() + "离线了。。");
                // 取消注册
                selectionKey.cancel();
                // 关闭通道
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 向其他客户端发送消息
     *
     * @param msg           消息
     * @param socketChannel 当前客户端的channel
     */
    public void sendMessageToOtherClient(String msg, SocketChannel socketChannel) throws IOException {
        System.out.println("服务器转发消息中");
        // 拿到所有注册的客户端
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            // 拿到通道
            Channel channel = key.channel();
            if (channel instanceof SocketChannel && Objects.equals(channel, socketChannel)) {
                continue;
            }
            ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
            // 将buffer数据写入通道
            if (channel instanceof ServerSocketChannel){
                continue;
            }
            SocketChannel socketChannel1 = (SocketChannel) channel;
            socketChannel1.write(buffer);
        }
    }

    public static void main(String[] args) {
        // 创建服务器对象
        GroupChatServer server = new GroupChatServer();
        server.listen();
    }
}
